package com.metro.paperless.common.interceptor;

import com.metro.core.beans.entity.BaseEntity;
import com.metro.paperless.common.beans.constant.CommonConstant;
import com.metro.paperless.common.utils.SequenceUtil;
import com.metro.paperless.common.utils.UserUtil;
import com.metro.utils.CollectionUtil;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

/**
 * 拦截器作用：给各实体对象在增加、修改时，自动添加操作属性信息。
 */
@Intercepts({@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class }) })
public class CommonAttrInterceptor implements Interceptor {

    protected Logger log = LoggerFactory.getLogger(CommonAttrInterceptor.class);
    @Override
    public Object intercept(Invocation invocation) throws Throwable
    {
        Object[] args = invocation.getArgs();
        MappedStatement ms = (MappedStatement)args[0];
        Object param = args[1];
        SqlCommandType sqlCommandType = ms.getSqlCommandType();
        switch (sqlCommandType){
            case INSERT:
                setSaveOrUpdateAttr(param, true);
                break;
            case UPDATE:
                setSaveOrUpdateAttr(param, false);
                break;
            case DELETE:
                if(param instanceof BaseEntity){
                    setDeleteAttr((BaseEntity)param);
                }
                break;
            default:
        }
        return invocation.proceed();

    }

    /**
     * 生成保存和修改的公共属性
     * @param param
     * @param save 是否是保存
     * @throws Throwable
     */
    private void setSaveOrUpdateAttr(Object param, boolean save) throws Throwable{
        if(param instanceof BaseEntity){
            BaseEntity entity = setSaveOrUpdateAttr((BaseEntity)param, save);
            if(entity.getId() == null){
                entity.setId(SequenceUtil.nextValue());
            }
        }else if(param instanceof Collection){
            setSaveOrUpdateAttr((Collection)param, save);
        }else if(param instanceof Map){
            setSaveOrUpdateAttr((Map)param, save);
        }
    }

    private void setSaveOrUpdateAttr(Map entity, boolean save)throws Throwable{
        if(entity != null && entity.entrySet() !=null){
            Iterator<Map.Entry> entryIterator = entity.entrySet().iterator();
            Map.Entry entry = null;
            while(entryIterator.hasNext()){
                entry = entryIterator.next();
                setSaveOrUpdateAttr(entry.getValue(), save);
            }
        }
    }

    private BaseEntity setSaveOrUpdateAttr(BaseEntity entity, boolean save)throws Throwable{
        if(save){
            if(entity.getId() == null){
                entity.setId(SequenceUtil.nextValue());
            }
            entity.setCreateUserId(UserUtil.getCurrUserId());
            entity.setCreateTime(new Date());
        }else{
            entity.setModifyUserId(UserUtil.getCurrUserId());
            entity.setModifyTime(new Date());
        }
        return entity;
    }

    private Collection setSaveOrUpdateAttr(Collection list, boolean save)throws Throwable{
        if(CollectionUtil.isNotEmpty(list)){
            for (Object obj : list ) {
                if(obj instanceof BaseEntity){
                    setSaveOrUpdateAttr((BaseEntity)obj, save);
                }else{
                    break;
                }
            }
        }
        return list;
    }



    private BaseEntity setDeleteAttr(BaseEntity entity){
        entity.setModifyUserId(UserUtil.getCurrUserId());
        entity.setModifyTime(new Date());
        entity.setDataStatus(CommonConstant.NO);
        return entity;
    }


    @Override
    public Object plugin(Object target)
    {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties)
    {

    }

}